Android进阶8:SharedPreferences原理分析

本文详细探讨了SharedPreferences的工作原理,包括其不适用于大量数据存储的原因、全量写入过程、跨进程安全性问题,以及在Android N之后对权限的支持变化。通过源码分析,解释了apply和commit的区别,以及可能导致ANR的情况。最后提到了腾讯的MMKV作为优化解决方案。
摘要由CSDN通过智能技术生成

关于SharePreferences(以下简称SP)的使用,相信从刚开发Android都开始使用了,但是对于SP的原理以及SP的缺点可能很多人没有系统的认知。
首先说一下SP的结论:

  1. 容易因此ANR:SP不适合存储数据量很大的信息;同时JSON以及HTML最好也不用SP存储,因为特殊字符转义是非常消耗性能的。
  2. 全量写入:在apply或者commit的时候,会先添加信息到内存中,在开启子线程,将内存中的信息写入到磁盘中(先清空磁盘该文件的信息,在全部写入)。
  3. 跨进程不安全:Sp没有跨进程的锁,就算使用MODE_MULTI_PROCESS,当频繁的操作SP时,也可能会造成数据丢失。
  4. 在Android N 之后 不再支持MODE_WORLD_READABLE, MODE_WORLD_WRITEABLE默认(不能被其他应读写)
  5. commit:当数据写入内存以及写入磁盘,都完成时调用listener。有返回值。 apply: 数据写入内存成功之后,在写入磁盘的过程中,直接调用listener,并不会等待写入磁盘完成。无返回值。

问题:

  1. SP为什么不适合存储很大的数据量?
  2. apply和commit的区别是否可以从源码中获得答案
  3. 为什么android7.0之后不支持MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE?
  4. 加载磁盘数据不是开启了子线程了吗? 那为什么还会造成ANR呢?

源码分析:

context.getSharedPreferences(String string, int mode);

我们知道实际上context的真正实现类是ContextImp,所以进入到ContextImp的getSharedPreferences方法查看:

    @Override
    public SharedPreferences getSharedPreferences(String name, int mode) {
        ......
        
        File file;
        synchronized (ContextImpl.class) {
            if (mSharedPrefsPaths == null) {
            	//定义类型:ArrayMap<String, File> mSharedPrefsPaths;
                mSharedPrefsPaths = new ArrayMap<>();
            }
            //从mSharedPrefsPaths中是否能够得到file文件
            file = mSharedPrefsPaths.get(name);
            if (file == null) {//如果文件为null
            	//就创建file文件
                file = getSharedPreferencesPath(name);
                将name,file键值对存入集合中
                mSharedPrefsPaths.put(name, file);
            }
        }
        return getSharedPreferences(file, mode);
    }

从上述代码可知,获取file文件,如果不存在就创建,存在就直接使用。其中mSharedPrefsPaths的泛型时:<String, File> , 顾名思义:<文件名,文件>。

   @Override
    public SharedPreferences getSharedPreferences(File file, int mode) {
    	//重点1
        checkMode(mode);
    	.......
        SharedPreferencesImpl sp;
        synchronized (ContextImpl.class) {
        	//获取缓存对象(或者创建缓存对象)
            final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
            //通过键file从缓存对象中获取Sp对象
            sp = cache.get(file);
            //如果是null,就说明缓存中还没后该文件的sp对象
            if (sp == null) {
            	//重点2:从磁盘读取文件
                sp = new SharedPreferencesImpl(file, mode);
                //添加到内存中
             
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值